﻿

using System.Linq.Expressions;
 

namespace PLCSharp.CoreModel.Tools
{
    public static class DeepCopyByExpressionTree
    {
        private static readonly Dictionary<Type, Delegate> _cache = [];
        public static T DeepCopy<T>(this T obj)
        {
            if (obj == null) return default;
            var type = typeof(T);
            if (!_cache.TryGetValue(type, out var func))
            {
                var parameter = Expression.Parameter(type, "p");
                var bindings = new List<MemberBinding>();
                foreach (var property in type.GetProperties())
                {
                    if (property.CanWrite)
                    {
                        var propertyAccess = Expression.Property(parameter, property);
                        var binding = Expression.Bind(property, propertyAccess);
                        bindings.Add(binding);
                    }

                }

                var memberInit = Expression.MemberInit(Expression.New(type), bindings);

                var lambda = Expression.Lambda<Func<T, T>>(memberInit, parameter);

                func = lambda.Compile();

                _cache[type] = func;

            }
            return ((Func<T, T>)func)(obj);
        }

    }

    public class XPoint
    {

        public double X { get; set; }

        public double Y { get; set; }

        public double Z { get; set; }
        public double Angle { get; set; }

        public static bool Equals(XPoint point1, XPoint point2)
        {
            return point1.X == point2.X 
                && point1.Y == point2.Y 
                && point1.Angle == point2.Angle;
        }
 

        public static XPoint GetOffsPoint(XPoint orign, double angle, XPoint before)
        {
            XPoint to = new();
            var t = Math.Atan2((orign.Y - before.Y), (orign.X - before.X)) * 180 / Math.PI;
            to.Angle = t + angle;
            var angleH = angle * Math.PI / 180;
            var x = before.X - orign.X;
            var y = before.Y - orign.Y;

            to.X = x * Math.Cos(angleH) + y * Math.Sin(angleH) + orign.X;
            to.Y = -x * Math.Sin(angleH) + y * Math.Cos(angleH) + orign.Y;
            return to;
        }

    }
}
